{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## **演示0202：矩阵与向量运算**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **案例1：数组内积和**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**两个一维数组的内积和**  \n",
    ">* 对应元素相乘然后再求和\n",
    ">* 向量的维度(元素个数)必须相同\n",
    ">* *np.dot(a, b)*或者*a.dot(b)*均可以计算内积和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "110\n",
      "110\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "a = np.array([1,2,3,4,5])\n",
    "b = np.array([2,4,6,8,10])\n",
    "print(a.dot(b))\n",
    "print(np.dot(a, b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**二维数组(矩阵)*A*与列向量*a*的乘积**  \n",
    ">* 将*a*视为一个一维数组，将矩阵*A*的第一行与*a*进行内积和操作，结果作为第一行(只有1个元素)\n",
    ">* *A*的第二行与*a*内积和，结果作为第二行(同样只有1个元素)\n",
    ">* 依次类推，维度为 *(N,M)* 的矩阵 *A* 与 *a* 乘积后，将生成一个具有 *N* 行的数组(每行只有1个元素),也即 *(N,1)* 列向量\n",
    ">* 要求*A*的列数*M*必须与*a*的长度相同"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 55]\n",
      " [130]\n",
      " [205]]\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[1,2,3,4,5], [6,7,8,9,10],[11,12,13,14,15]])    # (3,5)矩阵\n",
    "a = np.array([[1],[2],[3],[4],[5]])    # (5,1)列向量\n",
    "print(A.dot(a))    # (3,1)列向量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**二维数组(矩阵)*A*与一维数组*a*的内积和运算**  \n",
    ">* *A*的每一行(一维数组)，分别与*a*做内积和；各次操作结果形成一个一维数组\n",
    ">* 要求*A* 的列数必须与*a*的长度相同，否则无法进行内积运算\n",
    ">* 使用 *A.dot(a)* 或 *np.dot(A, a)* 均可\n",
    ">* 注意，此时的*a*仅是一位数组(不是列向量)，其结果也有所不同"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 550 1300 2050]\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[1,2,3,4,5], [6,7,8,9,10],[11,12,13,14,15]])\n",
    "a = np.array([10,20,30,40,50])\n",
    "print(A.dot(a))    # 维度为(3,)的一维数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **案例2：矩阵乘法**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **(M,N)维度矩阵 *A* 和 *(N,K)* 维度矩阵 *B* 相乘**  \n",
    ">* *A*的列数必须与*B*的行数相同\n",
    ">* 可理解为：\n",
    ">  * *A*的第1行与*B*的第1列进行内积和，结果作为第1行第1个元素\n",
    ">  * *A*的第1行与*B*的第2列进行内积和，结果作为第1行第2个元素\n",
    ">  * 依次类推，第1行一共产生了*K*个内积和\n",
    ">  * *A*的第2行与*B*的每一列分别执行上述操作，再次产生*K*个内积和\n",
    ">  * 直到*A*的最后一行与*B*的每一列计算完毕\n",
    ">  * 最终产生*(M,K)*结果矩阵\n",
    ">* *A.dot(B)*与*B.dot(A)*的含义是完全不同的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 55  55  55  55]\n",
      " [130 130 130 130]\n",
      " [205 205 205 205]]\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[1,2,3,4,5], [6,7,8,9,10],[11,12,13,14,15]])    # (3,5)\n",
    "B = np.array([[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4],[5,5,5,5]])    #(5,4)\n",
    "C = np.dot(A, B)    #(3,4)\n",
    "print(C)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**特殊维度的矩阵相乘**  \n",
    ">* *(M,1)* 矩阵与*(1,K)* 矩阵相乘，得到*(M,K)* 矩阵\n",
    ">* *(1,N)* 矩阵与*(N,K)* 矩阵相乘，得到*(1,K)* 矩阵\n",
    ">* *(1,N)* 矩阵与*(N,1)* 矩阵相乘，得到*(1,1)* 矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  2  3  4  5]\n",
      " [ 2  4  6  8 10]\n",
      " [ 3  6  9 12 15]\n",
      " [ 4  8 12 16 20]\n",
      " [ 5 10 15 20 25]]\n",
      "[[55]]\n",
      "[[55 55 55]]\n"
     ]
    }
   ],
   "source": [
    "A1 = np.array([[1],[2],[3],[4],[5]])  # (5,1)\n",
    "A2 = np.array([[1,2,3,4,5]])    # (1,5)\n",
    "A3 = np.array([[1,1,1],[2,2,2],[3,3,3],[4,4,4],[5,5,5]])   #(5,3)\n",
    "print(A1.dot(A2))    # (5, 5)\n",
    "print(A2.dot(A1))    # (1,1)。注意这个结果并不是一个标量，而是具有1行1列的二维数组(矩阵)\n",
    "print(A2.dot(A3))    # (1, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **案例3：一维数组与矩阵的乘积**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**维度为*(N,)*的一维数组*a*与二维数组*A*的乘积**  \n",
    ">* *a*与*A*中的每一列进行内积和，将所有结果放在一个一维数组中\n",
    ">* 要求*A*必须具有*N*行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[55 55 55]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([1,2,3,4,5])    # (5,)\n",
    "b = np.array([[1,1,1],[2,2,2],[3,3,3],[4,4,4],[5,5,5]])    # (5,3)\n",
    "print(a.dot(b))    # (3,)一维数组"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
